package com.demo.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.transaction.RabbitTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * 事务消息
 * 注意：rabbitmq 事务消息，不能作为分布式事务。rabbitmq事务消息只能保证多个消息要么同时投递成功，要不都不投递。但是它无法保证每个消息都
 * 可以成功的流转到消息队列中，也无法保证每一条消息都能被消费端成功消费！
 *
 * 注意：
 * 1、事务消息不能在application.yml文件中为 rabbitmq 生产者端配置确认参数（即下面两个配置参数），否则消息无法发送！
 *      #publisher-confirm-type: correlated
 *      #publisher-returns: true
 * 2、事务消息需要在消息发送的方法上增加 @Transactional 注解
 */
@Configuration
@Slf4j
public class RabbitConfig {

    public static final String EXCHANGE_NAME = "exchange.message.tx";
    public static final String QUEUE_NAME = "queue.message.tx";
    public static final String ROUTING_KEY = "routing.message.tx";

    /**
     * 配置事务消息
     * @param connectionFactory
     * @return
     */
    @Bean
    public RabbitTransactionManager transactionManager(CachingConnectionFactory connectionFactory){
        return new RabbitTransactionManager(connectionFactory);
    }

    @Bean
    public RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setChannelTransacted(true);
        return rabbitTemplate;
    }

    // 生产者启动时，自动创建消息队列
    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange(EXCHANGE_NAME, true, false);
    }

    @Bean
    public Queue txQueue(){
        return new Queue(QUEUE_NAME, true, false, false);
    }

    @Bean
    public Binding bindingTx(){
        return BindingBuilder.bind(txQueue()).to(directExchange()).with(ROUTING_KEY);
    }
}
